package com.specter.serv.service.impl;

import java.util.Map;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.DigestUtils;

import com.specter.mvc.model.dao.BaseDao;
import com.specter.serv.service.UserOauthService;
import com.specter.sure.core.AuthConsts;
import com.specter.sure.core.AuthContext;
import com.specter.sure.core.Authorized;
import com.specter.sure.core.StokenizorProvider;
import com.specter.utils.StringUtils;
import com.specter.utils.URLUtils;

import lombok.extern.slf4j.Slf4j;

/**
 * 
 * Note:本地认证提供机
 * 
 * @author Liang.Wang
 * @version 2018-09-30
 */
@Slf4j
@Service
@Transactional
public class UserOauthServiceImpl implements UserOauthService {
	private @Autowired BaseDao baseDao;
	protected @Autowired StokenizorProvider storage;

	@Override
	public Authorized getByClientId(String clientId) {
		// 1. 查询开发用户信息
		Authorized userd = baseDao.selectOne("com.specter.serv.entity.User.select_acid_info", clientId);
		String ips = clientId.split(":")[1];
		// 2. 网络地址是否匹配
		boolean isMatch = false;
		String ip = URLUtils.getRemoteAddr(AuthContext.getRequest());
		for (String rx : ips.split(",")) {
			if (URLUtils.ipMatch(ip, rx)) {
				isMatch = true;
				break;
			}
		}
		if (!isMatch) {
			log.debug("The client ip '{}' not match!", ip);
		}
		return isMatch ? userd : null;
	}

	@Override
	public boolean validateClientId(String clientId) {
		String key = AuthConsts.TOKEN_FROM_CACHE + ":oauth:client:" + clientId + ":object";
		Authorized client = storage.get(key, Authorized.class);
		if (client == null) { // 防止反复调用数据库
			client = this.getByClientId(clientId);
			storage.set(key, client, this.getExpireIn());
		}
		AuthContext.setUserDetail(client);
		return client != null;
	}

	@Override
	public boolean validateClientSg(String signature, String timestamp) {
		Authorized client = AuthContext.getUserDetail();
		if (StringUtils.isAnyBlank(signature, timestamp)) { return false; }
		if (client == null) { return false; }
		String ak = client.getUseruuid();
		String sk = client.getPassword();
		String sign = DigestUtils.md5DigestAsHex(("AK:%s/TS:%s/SK:%s".formatted(ak, timestamp, sk)).getBytes());
		log.debug("signature from client is:{}, signature from server is: {}", signature, sign);
		return sign.equals(signature);
	}

	@Override
	public boolean validateClientSk(String clientSecret) {
		Authorized client = AuthContext.getUserDetail();
		if (StringUtils.isBlank(clientSecret)) { return false; }
		if (client == null) { return false; }
		log.debug("secret from client is:{}, secret from server is: {}", clientSecret, client.getPassword());
		return clientSecret.equals(client.getPassword());
	}

	/* ------ auth_code 相关内容 ------ */
	@Override
	public void addAuthCode(String authCode, String clientId) {
		String key = AuthConsts.TOKEN_FROM_CACHE + ":oauth:code:" + authCode + ":string";
		storage.set(key, clientId, this.getExpireIn());
	}

	@Override
	public String getByAuthCode(String authCode) {
		String key = AuthConsts.TOKEN_FROM_CACHE + ":oauth:code:" + authCode + ":string";
		String clientId = storage.get(key, String.class);
		if (clientId != null) {
			storage.evict(authCode);// 只能使用一次
		}
		return clientId;
	}

	@Override
	public boolean validateAuthCode(String authCode) {
		String key = AuthConsts.TOKEN_FROM_CACHE + ":oauth:code:" + authCode + ":string";
		String clientId = storage.get(key, String.class);
		return clientId != null;
	}

	/* ------ access_token相关内容 ------ */
	@Override
	public String addAccessToken(String clientId) {
		String tokenKey = AuthConsts.TOKEN_FROM_CACHE + ":oauth:token:" + clientId + ":string";
		String accessToken = storage.get(tokenKey, String.class);
		if (accessToken == null) {
			String clientKey = AuthConsts.TOKEN_FROM_CACHE + ":oauth:client:" + clientId + ":object";
			Authorized client = storage.get(clientKey, Authorized.class);
			// 生成access_token
			accessToken = storage.tokenCreate(client.toMap(), this.getExpireIn());// UUID.randomUUID().toString();
			storage.set(tokenKey, accessToken, this.getExpireIn());// 设置为2个小时过期
		}
		return accessToken;
	}

	@Override
	public String getByAccessToken(String accessToken) {
		return null;
	}

	@Override
	public boolean validateAccessToken(String accessToken) {
		Map<String, String> map = storage.tokenValidate(accessToken);
		return map != null;
	}

	@Override
	public long getExpireIn() {
		return 60 * 60 * 2L;// 单位默认为秒
	}

}
